<div class=tcal>
<pre id="txt-cal" style="font-family: monospace; white-space: pre; font-size: 0.9em;"></pre>
</div>

<script>
const norm_array = [31,28,31,30,31,30,31,31,30,31,30,31];
const months = ["January","February","March","April","May","June",
                "July","August","September","October","November","December"];

function isLeap(year) {
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}

function getMonthArray(year, month) {
  let daysInMonth = norm_array[month];
  if (month === 1 && isLeap(year)) daysInMonth = 29;

  let firstDay = new Date(year, month, 1).getUTCDay(); // Mon=0 … Sun=6
  let grid = [];
  let day = 1;

  for (let w=0; w<6; w++) {
    grid[w] = [];
    for (let d=0; d<7; d++) {
      if (w===0 && d<firstDay) {
        grid[w][d] = "   ";
      } else if (day <= daysInMonth) {
        grid[w][d] = String(day++).padStart(3);
      } else {
        grid[w][d] = "   ";
      }
    }
  }
  return grid;
}

function getTextCalendar(year, month) {
  const monthArray = getMonthArray(year, month);

  // ngày hiện tại
  let now = new Date();
  let todayYear = now.getFullYear();
  let todayMonth = now.getMonth();
  let todayDate = now.getDate();

  let title = `────── ${months[month]} ${year} ──────\n\n`;
  let header = " Mon Tue Wed Thu Fri Sat Sun\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
  let body = monthArray.map(week => {
    return week.map(cell => {
      let num = cell.trim();
      if (num && year===todayYear && month===todayMonth && parseInt(num)===todayDate) {
        return `<span class="today">${cell}</span>`;
      } else {
        return cell;
      }
    }).join(" ");
  }).join("\n");

  return title + header + body;
}

// hiển thị tháng hiện tại khi load
let now = new Date();
let year_now = now.getFullYear();
let month_now = now.getMonth();

function render() {
  document.querySelector('#txt-cal').innerHTML = getTextCalendar(year_now, month_now);
}

render();

// thay đổi tháng bằng phím ← →
document.addEventListener('keydown', function(e) {
  if (e.keyCode === 37) { // left
    month_now--;
    if (month_now < 0) { month_now = 11; year_now--; }
    render();
  } else if (e.keyCode === 39) { // right
    month_now++;
    if (month_now > 11) { month_now = 0; year_now++; }
    render();
  }
});
</script>
<style>
footer {font-family: sans-serif; font-size: 11px; color: #858585;}
footer a {color: #436f9d;}
.today { color: #dcb622; position: relative; z-index: 1; }

.today::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 55px;
  height: 55px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle,
  rgba(255,255,150,0.6) 10%,
  rgba(255,200,0,0.2) 50%,
  rgba(255,255,150,0) 90%
);
  filter: blur(15px);
  animation: todayGlow 6s infinite alternate;
  z-index: -1;
}

@keyframes todayGlow {
  0% {
    transform: translate(-50%, -50%) scale(1);
    opacity: 0.3;
  }
  50% {
    transform: translate(-50%, -50%) scale(1.5);
    opacity: 0.6;
  }
  100% {
    transform: translate(-50%, -50%) scale(1);
    opacity: 0.3;
  }
}
</style>